using Kopernikus.Collections.Generic;
using Kopernikus.Parsing.Utility;

namespace Kopernikus.Parsing.GrammarSets
{
    public class SententialSymbolsAndProductions
    {
        private readonly IGrammar m_grammar;
        private Set<Production> m_sententialProductions;
        private Set<Symbol> m_sententialSymbols;


        public SententialSymbolsAndProductions(IGrammar grammar)
        {
            m_grammar = grammar;
        }

        public Set<Symbol> SententialSymbols
        {
            get
            {
                Calculate();
                return m_sententialSymbols;
            }
        }

        public Set<Production> SententialProductions
        {
            get
            {
                Calculate();
                return m_sententialProductions;
            }
        }

        private void Calculate()
        {
            if (m_sententialSymbols != null)
            {
                return;
            }
            m_sententialSymbols = new Set<Symbol>();
            m_sententialProductions = new Set<Production>();

            WorkList<Production> workList = new WorkList<Production>(true);
            workList.Enqueue(m_grammar.Productions);

            Production production;
            while (workList.Dequeue(out production))
            {
                if (m_sententialProductions.Contains(production))
                {
                    continue;
                }

                if (m_grammar.SymbolSets.TerminalSymbols.ContainsAny(production.RHS) ||
                    m_sententialSymbols.ContainsAny(production.RHS))
                {
                    m_sententialProductions.Add(production);
                    m_sententialSymbols.Add(production.LHS);
                    workList.Enqueue(m_grammar.ProductionSets.GetProductionsByRHS(production.LHS));
                }
            }
        }
    }
}